package com.lcy.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisIndexedHttpSession;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@EnableRedisIndexedHttpSession
@Configuration
public class SecurityConfiguration {


    @Resource
    private FindByIndexNameSessionRepository findByIndexNameSessionRepository;


    @Bean
    public SessionRegistry sessionRegistry() {
       return new SpringSessionBackedSessionRegistry(findByIndexNameSessionRepository);
     }



    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(requests -> requests.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                /**
                 * 会话管理，如果设置为1，则只能登录一个浏览器，否则会报错
                 * This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).
                 *  此方案适合前后端不分离的登录
                 *  会话失效的处理方案，让其跳转到登录页面
                 */
//                .sessionManagement(session -> session.maximumSessions(1).expiredUrl("/login"))


                /**
                 * 前后端分离的登录，以json的格式返回前端数据,
                 * 这种方式在单机的状态下可以，分布式情况下会失效的
                 */
                /*.sessionManagement(session -> session.maximumSessions(1).expiredSessionStrategy(
                        event -> {
                            HttpServletResponse response = event.getResponse();
                            response.setContentType("application/json;charset=utf-8");
                            PrintWriter writer = response.getWriter();
                            Map<String, Object> map = new HashMap<>();

                            map.put("code", 401);
                            map.put("message", "会话已过期");

                            writer.write(new ObjectMapper().writeValueAsString(map));
                            writer.flush();
                        }
                ))*/
                /**
                 * 在分布式情况下，可以这样解决
                 * SpringSecurity提供了一个SessionRegistry接口，专门用户解决集群会话的问题
                 * 将session数据保存到指定的地点，比如redis中，从而实现session的共享
                 * 再加上一个注解 @EnableRedisIndexedHttpSession
                 *
                 */
                .sessionManagement(session -> session.maximumSessions(1).sessionRegistry(sessionRegistry()))

        ;
        return http.build();
    }

}
